#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>

#define N 5
const short port = 3333;
const char ip[30] = "127.0.0.1";


typedef struct {
    char user[32];
    char password[32];
    int fd;
} Client;

Client clients[N];

int init() {
    int server = 0;
    if ((server = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("server failed to create socket");
        exit(1);
    }

    struct sockaddr_in addr;

    addr.sin_port = htons(port);
    addr.sin_family = PF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);

    if (bind(server, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("server failed to bind socket");
        exit(1);
    }

    if (listen(server, N) == -1) {
        perror("server failed to bind socket");
        exit(1);
    }

    printf("server started!\n");
    return server;

}

int get_user_account(const char *user) {
    for (int i = 0; i < N; i++) {
        if (strcmp(clients[i].user, user) == 0) {
            return i;
        }
    }
    return -1;
}

int get_empty_slot() {
    for (int i = 0; i < N; i++) {
        if (clients[i].fd == 0) {
            return i;
        }
    }
    return -1;
}

void *client_msg_handler(void *args) {
    int client = *(int *)args;

    const int buf_size = 128;
    char buf[buf_size];

    int num_bytes = 0;

    int idx = 0;

    num_bytes = recv(client, buf, buf_size, 0);

    if (num_bytes < 0) {
        perror("failed to receive client msg");
        exit(1);
    }

    if ((idx = get_user_account(buf)) < 0) {
        int cnt = get_empty_slot();
        if (cnt == -1) {
            perror("too many people");
            exit(1);
        }
        strcpy(clients[cnt].user, buf);
        clients[cnt].fd = client;
        buf[0] = 'n';
        buf[1] = '\0';
        if (send(client, buf, strlen(buf), 0) < 0) {
            perror("failed to send");
            exit(1);
        }

        num_bytes = recv(client, buf, buf_size, 0);

        if (num_bytes < 0) {
            perror("failed to receive password");
            exit(1);
        }
        buf[num_bytes] = '\0';
        strcpy(clients[cnt].password, buf);

        buf[0] = 'y';
        buf[1] = '\0';
        if (send(client, buf, strlen(buf), 0) < 0) {
            perror("failed to send confirm");
            exit(1);
        }
        idx = cnt;
        printf("register new user\n");

    }
    else {
        buf[0] = 'y';
        strcpy(buf + 1, clients[idx].password);

        if (send(client, buf, strlen(buf), 0) < 0) {
            perror("failed to send password");
            exit(1);
        }

        printf("login succeeded");
    }

    strcpy(buf, clients[idx].user);
    char *start = buf + strlen(clients[idx].user) + 1;
    size_t start_size = buf_size - (strlen(clients[idx].user) + 1);
    buf[strlen(clients[idx].user)] = ':';

    printf("new user:%s %s %d\n", clients[idx].user, clients[idx].password, clients[idx].fd);
    

    while (1) {
	memset(start, 0, start_size);
        if ((num_bytes = recv(client, start, start_size, 0)) <= 0) {
            for (int i = 0; i < N; i++) {
				if (client == clients[i].fd) {
					clients[i].fd =0 ;
                    printf("%s exit...\n", clients[i].user);
					clients[i].user[0] = '\0';
				}
			}
            
            pthread_exit(0);
        }

        //把消息分发到客户端
        for (int i = 0; i < N; i++) {
            
            if (clients[i].fd != 0 && clients[i].fd != client) {
                printf("send to %d\n", clients[i].fd);
                if (send(clients[i].fd, buf, strlen(buf), 0) < 0) {
                    perror("can't send msg");
                    exit(1);
                }
            }
        }
    }
}



void serve(int server) {
    while (1) {
		printf("waiting...\n");
		struct sockaddr_in clientaddr;
		socklen_t len = sizeof(clientaddr);
        int clientsocket = accept(server, (struct sockaddr*)&clientaddr, &len);
        if (clientsocket == -1) {
			perror("error when connecting...\n");
            continue;
        }
        else {
            pthread_t tid;
            pthread_create(&tid, 0, client_msg_handler, &clientsocket);
        }
    }

}


int main() {
    int server = init();
    serve(server);
    return 0;

}
